/**
 * Copyright 2018 orivil.com. All rights reserved.
 * Use of this source code is governed by a MIT-style
 * license that can be found at https://mit-license.org.
 */

package db

import (
	"fmt"
	"gitee.com/tugoer/orivil/mux"
	"github.com/jinzhu/gorm"
	_ "github.com/lib/pq"
	_ "github.com/go-sql-driver/mysql"
	"errors"
	"gitee.com/tugoer/orivil/config"
	"gitee.com/tugoer/orivil/log"
)

type Env struct {
	Log               bool   `json:"log"`
	Dialect string `json:"dialect"`
	Host              string `json:"host"`
	Port              string `json:"port"`
	User              string `json:"user"`
	Password          string `json:"password"`
	DBName            string `json:"db_name"`
	SSL bool `json:"ssl"`
	SqlTablePrefix    string `json:"sql_table_prefix"`
	MaxIdleConnects   int    `json:"max_idle_connects"`
	MaxOpenedConnects int    `json:"max_opened_connects"`
}

var Gorm = func() *gorm.DB{
	env := &Env{
		SqlTablePrefix:    "",
		MaxIdleConnects:   5,
		MaxOpenedConnects: 50,
	}
	// 读取配置
	parser := config.NewJsonParser("configs")
	err := parser.ReadOrCreate("db", &env)
	if err != nil {
		log.Emergency.Panic(err)
	}
	return InitDB(env)
}()

func InitDB(env *Env) *gorm.DB {
	// 设置表前缀
	if env.SqlTablePrefix != "" {
		gorm.DefaultTableNameHandler = func(db *gorm.DB, defaultTableName string) string {
			return env.SqlTablePrefix + defaultTableName
		}
	}

	var arg string
	switch env.Dialect {
	case "":
		panic(errors.New("configs/db.json 没有数据库配置信息"))
	case "mysql":
		arg = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=True&loc=Local", env.User, env.Password, env.Host, env.Port, env.DBName)
	case "postgres":
		arg = fmt.Sprintf("user=%s password=%s host=%s port=%s dbname=%s", env.User, env.Password, env.Host, env.Port, env.DBName)
		if !env.SSL {
			arg += " sslmode=disable"
		}
	default:
		panic(errors.New("目前只支持 postgres 或 mysql 数据库"))
	}

	db, err := gorm.Open(env.Dialect, arg)
	if err != nil {
		panic(err)
	}
	db.LogMode(env.Log)
	db.DB().SetMaxIdleConns(env.MaxIdleConnects)
	db.DB().SetMaxOpenConns(env.MaxOpenedConnects)
	if err = db.DB().Ping(); err != nil {
		panic(err)
	}

	// 注册关闭事件
	mux.BeforeClose(func() {
		log.Info.Printf("关闭数据库[%s]连接...\n", env.DBName)
		db.Close()
		log.Info.Printf("done\n")
	})
	return db
}